﻿Imports SlimDX
Imports SlimDX.Direct3D9
Imports System.IO

Public Class BSP
    Implements IRenderable
    Public vCenter As Vector3
    Dim Surfaces() As Short
    Public Lightmaps() As StructureLightmaps
    Public lBitmaps() As Texture
    Public lightmapTag As Magic.Core.Tag
    Public Originals As Byte()
    Public Name As String
    Public Tag As Magic.Core.Tag

    Public Planes() As Plane
    Sub Dispose()
        For x As Integer = 0 To lBitmaps.Count - 1
            lBitmaps(x).Dispose()
        Next
        For l As Integer = 0 To Lightmaps.Count - 1
            For m As Integer = 0 To Lightmaps(l).Materials.Count - 1
                If Not Lightmaps(l).Materials(m).lMesh Is Nothing Then
                    Lightmaps(l).Materials(m).lMesh.Dispose()
                End If
                If Not Lightmaps(l).Materials(m).Shader Is Nothing Then
                    'Lightmaps(l).Materials(m).Shader.Dispose()
                End If
            Next
        Next
    End Sub
    Sub InitLightmaps(Optional ByVal index As Integer = -1)
        If index > -1 Then
            Dim nBitmap As New Bitmap(lightmapTag)
            lBitmaps(index) = nBitmap.Texture(index, True)
        Else
            Dim nBitmap As New Bitmap(lightmapTag)
            ReDim lBitmaps(nBitmap.Count - 1)
            For x As Integer = 0 To nBitmap.Count - 1
                lBitmaps(x) = nBitmap.Texture(x, True)
            Next
        End If

    End Sub
    Sub Changed(ByVal bsptag As Magic.Core.Tag)
        Dim worldX As Single() = bsptag("world bounds x")
        Dim worldY As Single() = bsptag("world bounds y")
        Dim worldZ As Single() = bsptag("world bounds z")

        vCenter = New Vector3((worldX(1) + worldX(0)) / 2, (worldY(1) + worldY(0)) / 2, (worldZ(1) + worldZ(0)) / 2)

        lightmapTag = magicMap.Library(bsptag("lightmaps"))

        If Not lightmapTag Is Nothing Then
            Originals = lightmapTag(19)
            InitLightmaps()
        End If

        Name = bsptag.Name

        Dim SurfaceBlock As Array = bsptag("surfaces")
        Dim surfaceCount As Integer = SurfaceBlock.GetLength(0)

        ReDim Surfaces(surfaceCount * 3 - 1)
        For x As Integer = 0 To surfaceCount - 1
            Surfaces(x * 3) = SurfaceBlock.GetValue(x, 0)
            Surfaces(x * 3 + 1) = SurfaceBlock.GetValue(x, 1)
            Surfaces(x * 3 + 2) = SurfaceBlock.GetValue(x, 2)
        Next


        Dim LightmapBlock As Array = bsptag("structure lightmaps")
        Dim LightmapCount As Integer = LightmapBlock.GetLength(0)

        ReDim Lightmaps(LightmapCount - 1)
        For x As Integer = 0 To LightmapCount - 1
            Lightmaps(x) = New StructureLightmaps(x, LightmapBlock)
        Next
        CreateMesh()
    End Sub
    Sub New(ByVal bspTag As Magic.Core.Tag)
        AddHandler bspTag.TagHasChanged, AddressOf Changed
        Tag = bspTag

        Dim worldX As Single() = bspTag("world bounds x")
        Dim worldY As Single() = bspTag("world bounds y")
        Dim worldZ As Single() = bspTag("world bounds z")

        vCenter = New Vector3((worldX(1) + worldX(0)) / 2, (worldY(1) + worldY(0)) / 2, (worldZ(1) + worldZ(0)) / 2)

        lightmapTag = magicMap.Library(bspTag("lightmaps"))

        If Not lightmapTag Is Nothing Then
            Originals = lightmapTag(19)
            InitLightmaps()
        End If

        Name = bspTag.Name

        Dim SurfaceBlock As Array = bspTag("surfaces")
        Dim surfaceCount As Integer = SurfaceBlock.GetLength(0)

        ReDim Surfaces(surfaceCount * 3 - 1)
        For x As Integer = 0 To surfaceCount - 1
            Surfaces(x * 3) = SurfaceBlock.GetValue(x, 0)
            Surfaces(x * 3 + 1) = SurfaceBlock.GetValue(x, 1)
            Surfaces(x * 3 + 2) = SurfaceBlock.GetValue(x, 2)
        Next

        Dim CollisionBlock As Array = bspTag("collision bsp")

        Dim PlaneBlock As Array = CollisionBlock.GetValue(0, 1)

        Dim planeCount As Integer = PlaneBlock.GetLength(0)

        ReDim Planes(planeCount - 1)
        For x As Integer = 0 To planeCount - 1
            Planes(x) = New Plane(PlaneBlock.GetValue(x, 0)(0), PlaneBlock.GetValue(x, 0)(1), PlaneBlock.GetValue(x, 0)(2), PlaneBlock.GetValue(x, 0)(3))
        Next


        Dim LightmapBlock As Array = bspTag("structure lightmaps")
        Dim LightmapCount As Integer = LightmapBlock.GetLength(0)

        ReDim Lightmaps(LightmapCount - 1)
        For x As Integer = 0 To LightmapCount - 1
            Lightmaps(x) = New StructureLightmaps(x, LightmapBlock)
        Next
        CreateMesh()
    End Sub
    Public Function FindClusterForPoint(P As Vector3) As Integer
        Return traverseBspTree(0, P)
    End Function
    Function traverseBspTree(node As Integer, P As Vector3) As Integer
        If (node = -1) Then ' I'm still not 100% sure what -1 means, but I'm almost positive it means that the point fell outside the BSP.
            Return -1
        End If
        If (node < 0) Then '// we've hit a leaf, return the cluster 
            'return Leaves[node &0x7FFFFFFF].cluster;
        End If

        Dim N As Plane = Nothing 'getPlane(Node3d[node].plane);
        Dim d As Single = Plane.DotNormal(N, P) - N.D ' // if this is < 0 the point is behind the plane, if > 0 it's in front
        'If (d > 0) Then return traverseBspTree(Node3d[node].frontNode, P)
        'return traverseBspTree(Node3d[node].backNode, P)
    End Function
    Public Sub Render(ByVal xDevice As Device) Implements IRenderable.Render
        For l As Integer = 0 To Lightmaps.Count - 1
            If Lightmaps(l).bitmapIndex > -1 Then
                'xDevice.SamplerState(0).MinFilter = TextureFilter.Linear
                'xDevice.SamplerState(0).MagFilter = TextureFilter.Linear
                'xDevice.SamplerState(0).MipFilter = TextureFilter.Linear
                'xDevice.SetTexture(0, lBitmaps(Lightmaps(l).bitmapIndex))
                'xDevice.TextureState(0).TextureCoordinateIndex = 1
                'xDevice.TextureState(0).ColorOperation = TextureOperation.SelectArg1
                'xDevice.TextureState(0).ColorArgument1 = TextureArgument.TextureColor
            Else
                'xDevice.SetTexture(0, Nothing)
            End If
            For m As Integer = 0 To Lightmaps(l).Materials.Count - 1
                If Not Lightmaps(l).Materials(m).lMesh Is Nothing Then
                    If Lightmaps(l).Materials(m).Render Then
                        If BoxInFrustum(Lightmaps(l).Materials(m).bBox_Max, Lightmaps(l).Materials(m).bBox_Min) Then
                            xDevice.SetTransform(TransformState.World, Matrix.Identity)
                            If Not Lightmaps(l).Materials(m).Shader Is Nothing Then
                                Dim lMap As Texture = Nothing
                                If Lightmaps(l).bitmapIndex > -1 Then
                                    lMap = lBitmaps(Lightmaps(l).bitmapIndex)
                                End If

                                Dim nShader As IShader = Lightmaps(l).Materials(m).Shader

                                Dim numpasses As Integer = nShader.BeginShader(lMap)
                                For pass As Integer = 0 To numpasses - 1
                                    nShader.BeginPass(pass)
                                    Lightmaps(l).Materials(m).lMesh.DrawSubset(0)
                                    nShader.EndPass()
                                Next
                                nShader.EndShader()

                            Else
                                Lightmaps(l).Materials(m).lMesh.DrawSubset(0)
                            End If
                        End If
                    End If
                End If

            Next
        Next
    End Sub
    Public Sub CreateMesh()
        For l As Integer = 0 To Lightmaps.Count - 1
            If Lightmaps(l).Materials.Count > 0 Then
                For m As Integer = 0 To Lightmaps(l).Materials.Count - 1
                    Lightmaps(l).Materials(m).CreateMesh(Surfaces)
                Next
            End If
        Next
    End Sub
    Function GetVector(ByVal pX As Integer, ByVal pY As Integer) As Vector3

        Dim nRay As Ray = CreateRay(Matrix.Identity, pX, pY)
        Dim closestDistance As Single = Single.MaxValue
        Dim currentDistance As Single = Single.MaxValue
        Dim faceIndex As Integer
        Dim iInfo As IntersectInformation
        Dim iInfos() As IntersectInformation = Nothing

        Dim a As PositionTexture
        Dim b As PositionTexture
        Dim c As PositionTexture
        Dim hitBSP As Boolean = False

        For x As Integer = 0 To Lightmaps.Length - 1
            For m As Integer = 0 To Lightmaps(x).Materials.Count - 1
                If Not IsNothing(Lightmaps(x).Materials(m).lMesh) Then
                    If Lightmaps(x).Materials(m).lMesh.Intersects(nRay, currentDistance, faceIndex, iInfos) Then
                        If currentDistance < closestDistance Then
                            iInfo = iInfos(iInfos.Length - 1)
                            closestDistance = currentDistance
                            a = Lightmaps(x).Materials(m).Verts(Lightmaps(x).Materials(m).Faces(faceIndex * 3))
                            b = Lightmaps(x).Materials(m).Verts(Lightmaps(x).Materials(m).Faces(faceIndex * 3 + 1))
                            c = Lightmaps(x).Materials(m).Verts(Lightmaps(x).Materials(m).Faces(faceIndex * 3 + 2))
                            hitBSP = True
        End If
        End If
                End If
            Next
        Next

        If hitBSP Then
            Dim position As Vector3 = Vector3.Barycentric(New Vector3(a.X, a.Y, a.Z), New Vector3(b.X, b.Y, b.Z), New Vector3(c.X, c.Y, c.Z), iInfo.U, iInfo.V)
            Dim normal As Vector3 = Vector3.Barycentric(New Vector3(a.nX, a.nY, a.nZ), New Vector3(b.nX, b.nY, b.nZ), New Vector3(c.nX, c.nY, c.nZ), iInfo.U, iInfo.V)
            normal = Vector3.Multiply(normal, 0.02F)
            Dim vPosition As Vector3 = New Vector3(position.X + normal.X, position.Y + normal.Y, position.Z + normal.Z)
            Return vPosition 'New Vector3(b.X, b.Y, b.Z)
        End If
        Return Camera.Position
    End Function
    Function GetColor(ByVal vPosition As Vector3) As Color
        Dim closestDistance As Single = Single.MaxValue
        Dim currentDistance As Single = Single.MaxValue
        Dim faceIndex As Integer
        Dim nRay As New Ray(vPosition, New Vector3(0.0F, 0.0F, -1.0F))
        Dim iInfo As IntersectInformation
        Dim iInfos() As IntersectInformation = Nothing

        Dim a As PositionTexture
        Dim b As PositionTexture
        Dim c As PositionTexture
        Dim hitBSP As Boolean = False
        Dim lightMap As Integer = -1

        For x As Integer = 0 To Lightmaps.Length - 1
            For m As Integer = 0 To Lightmaps(x).Materials.Count - 1
                If Not IsNothing(Lightmaps(x).Materials(m).lMesh) Then
                    If Lightmaps(x).Materials(m).lMesh.Intersects(nRay, currentDistance, faceIndex, iInfos) Then
                        If currentDistance < closestDistance Then
                            iInfo = iInfos(iInfos.Length - 1)
                            closestDistance = currentDistance
                            a = Lightmaps(x).Materials(m).Verts(Lightmaps(x).Materials(m).Faces(faceIndex * 3))
                            b = Lightmaps(x).Materials(m).Verts(Lightmaps(x).Materials(m).Faces(faceIndex * 3 + 1))
                            c = Lightmaps(x).Materials(m).Verts(Lightmaps(x).Materials(m).Faces(faceIndex * 3 + 2))
                            hitBSP = True
                            lightMap = Lightmaps(x).bitmapIndex
                        End If
                    End If
                End If
            Next
        Next

        If hitBSP Then
            If lightMap > -1 Then
                Dim uvPosition As Vector2 = Vector2.Barycentric(New Vector2(a.u2, a.v2), New Vector2(b.u2, b.v2), New Vector2(c.u2, c.v2), iInfo.U, iInfo.V)
                Dim nBitmap As New System.Drawing.Bitmap(Texture.ToStream(lBitmaps(lightMap), ImageFileFormat.Jpg))
                Return nBitmap.GetPixel(uvPosition.X * nBitmap.Width, uvPosition.Y * nBitmap.Height)
            End If
        End If
        Return Color.White
    End Function
    Function SetColor(ByVal pX As Integer, ByVal pY As Integer, ByVal vColor As Color)
        Dim closestDistance As Single = Single.MaxValue
        Dim currentDistance As Single = Single.MaxValue
        Dim faceIndex As Integer
        Dim nRay As Ray = CreateRay(Matrix.Identity, pX, pY)
        Dim iInfo As IntersectInformation
        Dim iInfos() As IntersectInformation = Nothing

        Dim a As PositionTexture
        Dim b As PositionTexture
        Dim c As PositionTexture
        Dim hitBSP As Boolean = False
        Dim lightMap As Integer = -1

        For x As Integer = 0 To Lightmaps.Length - 1
            For m As Integer = 0 To Lightmaps(x).Materials.Count - 1
                If Not IsNothing(Lightmaps(x).Materials(m).lMesh) Then
                    If Lightmaps(x).Materials(m).lMesh.Intersects(nRay, currentDistance, faceIndex, iInfos) Then
                        If currentDistance < closestDistance Then
                            iInfo = iInfos(iInfos.Length - 1)
                            closestDistance = currentDistance
                            a = Lightmaps(x).Materials(m).Verts(Lightmaps(x).Materials(m).Faces(faceIndex * 3))
                            b = Lightmaps(x).Materials(m).Verts(Lightmaps(x).Materials(m).Faces(faceIndex * 3 + 1))
                            c = Lightmaps(x).Materials(m).Verts(Lightmaps(x).Materials(m).Faces(faceIndex * 3 + 2))
                            hitBSP = True
                            lightMap = Lightmaps(x).bitmapIndex
                        End If
                    End If
                End If
            Next
        Next

        If hitBSP Then
            If lightMap > -1 Then
                Dim uvPosition As Vector2 = Vector2.Barycentric(New Vector2(a.u2, a.v2), New Vector2(b.u2, b.v2), New Vector2(c.u2, c.v2), iInfo.U, iInfo.V)
                'Dim nBitmap As New System.Drawing.Bitmap(Texture.ToStream(lBitmaps(lightMap), ImageFileFormat.Jpg))

                Dim comInt As Integer = CompressColor(vColor)
                Dim DDSWay As Boolean = True
                If Not DDSWay Then
                    Dim Raw(lightmapTag("bitmaps").GetValue(lightMap, 10)(1)) As Byte
                    Array.Copy(lightmapTag("bitmaps").GetValue(lightMap, 19), lightmapTag("bitmaps").GetValue(lightMap, 10)(0), Raw, 0, Raw.Length)

                    Dim BitmapWidth As Integer = lightmapTag("bitmaps").GetValue(lightMap, 1)
                    Dim BitmapHeight As Integer = lightmapTag("bitmaps").GetValue(lightMap, 2)
                    Dim bFormat As Bitmap.bitmFormat = lightmapTag("bitmaps").GetValue(lightMap, 5)

                    Dim bFlags As Bitmap.bitmType = lightmapTag("bitmaps").GetValue(lightMap, 6)
                    If (bFlags And &H8) > 0 Then
                        Select Case bFormat
                            Case Bitmap.bitmFormat.BITM_FORMAT_DXT1
                                Raw = Raw
                            Case Bitmap.bitmFormat.BITM_FORMAT_DXT2AND3
                                Raw = Raw
                            Case Bitmap.bitmFormat.BITM_FORMAT_DXT4AND5
                                Raw = Raw
                            Case Bitmap.bitmFormat.BITM_FORMAT_A8
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 8, SwizzleType.DeSwizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_Y8
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 8, SwizzleType.DeSwizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_AY8
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 8, SwizzleType.DeSwizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_A8Y8
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 16, SwizzleType.DeSwizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_R5G6B5
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 16, SwizzleType.DeSwizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_A1R5G5B5
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 16, SwizzleType.DeSwizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_A4R4G4B4
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 16, SwizzleType.DeSwizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_X8R8G8B8
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 32, SwizzleType.DeSwizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_A8R8G8B8
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 32, SwizzleType.DeSwizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_P8
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 8, SwizzleType.DeSwizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_A8_LIGHTMAP
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 8, SwizzleType.DeSwizzle)
                        End Select
                    End If
                    Dim rX As Integer = CInt(CSng(BitmapWidth - 1) * uvPosition.X)
                    Dim rY As Integer = CInt(CSng(BitmapHeight - 1) * uvPosition.Y)

                    Dim DestIndex As Integer = ((rY * BitmapWidth + rX) * 2 - 2)
                    Array.Copy(BitConverter.GetBytes(BitConverter.ToInt16(BitConverter.GetBytes(comInt), 0)), 0, Raw, DestIndex, 2)
                    If (bFlags And &H8) > 0 Then
                        Select Case bFormat
                            Case Bitmap.bitmFormat.BITM_FORMAT_DXT1
                                Raw = Raw
                            Case Bitmap.bitmFormat.BITM_FORMAT_DXT2AND3
                                Raw = Raw
                            Case Bitmap.bitmFormat.BITM_FORMAT_DXT4AND5
                                Raw = Raw
                            Case Bitmap.bitmFormat.BITM_FORMAT_A8
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 8, SwizzleType.Swizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_Y8
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 8, SwizzleType.Swizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_AY8
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 8, SwizzleType.Swizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_A8Y8
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 16, SwizzleType.Swizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_R5G6B5
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 16, SwizzleType.Swizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_A1R5G5B5
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 16, SwizzleType.Swizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_A4R4G4B4
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 16, SwizzleType.Swizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_X8R8G8B8
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 32, SwizzleType.Swizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_A8R8G8B8
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 32, SwizzleType.Swizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_P8
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 8, SwizzleType.Swizzle)
                            Case Bitmap.bitmFormat.BITM_FORMAT_A8_LIGHTMAP
                                Raw = Swizzle.Swizzle(Raw, BitmapWidth, BitmapHeight, -1, 8, SwizzleType.Swizzle)
                        End Select
                    End If
                    lightmapTag("bitmaps").setValue(Raw, lightMap, 11)
                    InitLightmaps(lightMap)
                Else
                    Dim nBytes() As Byte = BitConverter.GetBytes(comInt)

                    Dim desc As SurfaceDescription = lBitmaps(lightMap).GetLevelDescription(0)
                    Dim surf As Surface = lBitmaps(lightMap).GetSurfaceLevel(0)
                    Dim rX As Integer = CInt(CSng(desc.Width - 1) * uvPosition.X)
                    Dim rY As Integer = CInt(CSng(desc.Height - 1) * uvPosition.Y)

                    Dim dRectangle As DataRectangle = surf.LockRectangle(LockFlags.None)

                    dRectangle.Data.Position = ((rY * desc.Width) + rX) * 2 - 2
                    dRectangle.Data.Write(nBytes, 0, 2)
                    surf.UnlockRectangle()
                End If

            End If
        End If
        Return Color.White
    End Function
    Function SetShader(ByVal pX As Integer, ByVal pY As Integer, ByVal vIndex As Integer)
        Dim closestDistance As Single = Single.MaxValue
        Dim currentDistance As Single = Single.MaxValue
        Dim faceIndex As Integer
        Dim nRay As Ray = CreateRay(Matrix.Identity, pX, pY)
        Dim iInfo As IntersectInformation
        Dim iInfos() As IntersectInformation = Nothing

        Dim a As PositionTexture
        Dim b As PositionTexture
        Dim c As PositionTexture
        Dim hitBSP As Boolean = False
        Dim lightMap As Integer = -1
        Dim materials As Integer = -1

        For x As Integer = 0 To Lightmaps.Length - 1
            For m As Integer = 0 To Lightmaps(x).Materials.Count - 1
                If Not IsNothing(Lightmaps(x).Materials(m).lMesh) Then
                    If Lightmaps(x).Materials(m).lMesh.Intersects(nRay, currentDistance, faceIndex, iInfos) Then
                        If currentDistance < closestDistance Then
                            iInfo = iInfos(iInfos.Length - 1)
                            closestDistance = currentDistance
                            a = Lightmaps(x).Materials(m).Verts(Lightmaps(x).Materials(m).Faces(faceIndex * 3))
                            b = Lightmaps(x).Materials(m).Verts(Lightmaps(x).Materials(m).Faces(faceIndex * 3 + 1))
                            c = Lightmaps(x).Materials(m).Verts(Lightmaps(x).Materials(m).Faces(faceIndex * 3 + 2))
                            hitBSP = True
                            lightMap = x
                            materials = m
                        End If
                    End If
                End If
            Next
        Next

        If hitBSP Then
            If lightMap > -1 Then
                Dim LightmapBlock As Array = Tag("structure lightmaps")

                Dim MaterialBlock As Array = LightmapBlock.GetValue(lightMap, 3)

                MaterialBlock.SetValue(vIndex, materials, 0)

                Lightmaps(lightMap).Materials(materials).ShaderIndex = vIndex

                Lightmaps(lightMap).Materials(materials).Shader = Managers.ReturnShader(vIndex)
                Tag.Dirty()
            End If
        End If
        Return Color.White
    End Function
    Public Class StructureLightmaps
        Public bitmapIndex As Short
        Public Materials() As StructureMaterials
        Sub New(ByVal index As Integer, ByVal tagArray As Array)
            bitmapIndex = tagArray.GetValue(index, 0)
            Dim MaterialBlock As Array = tagArray.GetValue(index, 3)
            Dim MaterialCount As Integer = MaterialBlock.GetLength(0)
            ReDim Materials(MaterialCount - 1)
            For x As Integer = 0 To MaterialCount - 1
                Materials(x) = New StructureMaterials(x, MaterialBlock)
            Next

        End Sub

        Public Class StructureMaterials
            Public Shader As IShader
            Public ShaderIndex As Integer
            Dim SurfacesStart As Integer
            Dim SurfacesCount As Integer
            Public Faces() As Short
            Public Verts() As PositionTexture
            Public lMesh As Mesh
            Public bBox_Min, bBox_Max As Vector3
            Public Render As Boolean = True
            Sub New(ByVal index As Integer, ByVal tagArray As Array)
                bBox_Max = New Vector3(Single.MaxValue, Single.MaxValue, Single.MaxValue)
                bBox_Min = New Vector3(Single.MinValue, Single.MinValue, Single.MinValue)

                ShaderIndex = tagArray(index, 0)

                Shader = Managers.ReturnShader(ShaderIndex)

                SurfacesStart = tagArray(index, 3) * 3
                SurfacesCount = tagArray(index, 4) * 3

                Dim VerticeCount As Integer = tagArray(index, 20)(1)
                Dim LightmapCount As Integer = tagArray(index, 21)(1)
                Dim Compressed As Boolean = True
                Dim VertexBytes() As Byte = CType(tagArray(index, 23), Magic.Core.Tag.DataContainer).data
                If VertexBytes.Length = 0 Then
                    Compressed = False
                    VertexBytes = CType(tagArray(index, 22), Magic.Core.Tag.DataContainer).data
                End If
                Dim BR As New System.IO.BinaryReader(New System.IO.MemoryStream(VertexBytes))
                ReDim Verts(VerticeCount - 1)
                For z As Integer = 0 To VerticeCount - 1
                    Dim nVert As New PositionTexture
                    nVert.X = BR.ReadSingle
                    nVert.Y = BR.ReadSingle
                    nVert.Z = BR.ReadSingle

                    If nVert.X > bBox_Max.X Then
                        bBox_Max.X = nVert.X
                    End If
                    If nVert.Y > bBox_Max.Y Then
                        bBox_Max.Y = nVert.Y
                    End If
                    If nVert.Z > bBox_Max.Z Then
                        bBox_Max.Z = nVert.Z
                    End If

                    If nVert.X < bBox_Min.X Then
                        bBox_Min.X = nVert.X
                    End If
                    If nVert.Y < bBox_Min.Y Then
                        bBox_Min.Y = nVert.Y
                    End If
                    If nVert.Z < bBox_Min.Z Then
                        bBox_Min.Z = nVert.Z
                    End If


                    If Compressed Then
                        Dim Normals() As Single = Decompress(BR.ReadInt32)
                        nVert.nX = Normals(0)
                        nVert.nY = Normals(1)
                        nVert.nZ = Normals(2)

                        Dim BiNormals() As Single = Decompress(BR.ReadInt32)
                        nVert.bX = BiNormals(0)
                        nVert.bY = BiNormals(1)
                        nVert.bZ = BiNormals(2)

                        Dim tempint As Integer = BR.ReadInt32
                        Dim Tangent() As Single = Decompress(tempint)
                        Dim Tangent2() As Single = Magic.Core.HaloMap.DecompressNew(tempint)
                        nVert.tX = Tangent(0)
                        nVert.tY = Tangent(1)
                        nVert.tZ = Tangent(2)
                    Else
                        nVert.nX = BR.ReadSingle
                        nVert.nY = BR.ReadSingle
                        nVert.nZ = BR.ReadSingle

                        nVert.bX = BR.ReadSingle
                        nVert.bY = BR.ReadSingle
                        nVert.bZ = BR.ReadSingle

                        nVert.tX = BR.ReadSingle
                        nVert.tY = BR.ReadSingle
                        nVert.tZ = BR.ReadSingle
                    End If
                    nVert.u1 = BR.ReadSingle
                    nVert.v1 = BR.ReadSingle
                    Verts(z) = nVert
                Next
                If BR.BaseStream.Position < BR.BaseStream.Length Then
                    For z As Integer = 0 To LightmapCount - 1
                        Dim nVert As PositionTexture = Verts(z)
                        If Compressed Then
                            BR.BaseStream.Position += 4
                            nVert.u2 = DecompressShortToFloat(BR.ReadInt16)
                            nVert.v2 = DecompressShortToFloat(BR.ReadInt16)
                        Else
                            BR.BaseStream.Position += 12
                            nVert.u2 = BR.ReadSingle
                            nVert.v2 = BR.ReadSingle
                        End If
                        Verts(z) = nVert
                    Next
                End If
            End Sub
            Sub CreateMesh(ByVal gSurfaces() As Short)
                ReDim Faces(SurfacesCount - 1)
                'For s As Integer = 0 To SurfacesCount - 1
                ' Faces(s) = gSurfaces(SurfacesStart + s)
                ' Next
                Array.Copy(gSurfaces, SurfacesStart, Faces, 0, SurfacesCount)

                lMesh = New Mesh(xDevice, Faces.Length, Verts.Length, MeshFlags.Managed, PositionTexture.Format)
                'lMesh.VertexBuffer.SetData(Verts, 0, LockFlags.None)
                'lMesh.IndexBuffer.SetData(Faces, 0, LockFlags.None)
                Dim ds As DataStream = lMesh.LockVertexBuffer(LockFlags.None)
                ds.WriteRange(Verts)
                lMesh.UnlockVertexBuffer()
                ds = lMesh.LockIndexBuffer(LockFlags.None)
                ds.WriteRange(Faces)
                lMesh.UnlockIndexBuffer()
                'Optimize Mesh
                'Dim pAdj(lMesh.NumberFaces * 3 - 1) As Integer
                'lMesh.GenerateAdjacency(0.0, pAdj)
                'lMesh.OptimizeInPlace(MeshFlags.OptimizeCompact Or MeshFlags.OptimizeVertexCache, pAdj)
                'pAdj = Nothing

                'Dim gData As GraphicsStream = lMesh.LockVertexBuffer(LockFlags.ReadOnly)
                'Geometry.ComputeBoundingBox(gData, lMesh.NumberVertices, PositionTexture.Format, bBox_Min, bBox_Max)
                'lMesh.UnlockVertexBuffer()

                'Dim Temp(0) As Integer
                'Temp(0) = lMesh.NumberVertices
                'Verts = lMesh.LockVertexBuffer(GetType(PositionTexture), LockFlags.ReadOnly, Temp)
                'lMesh.UnlockVertexBuffer()
            End Sub

        End Class
    End Class
End Class
